// funcs
package glutil

import (
	"encoding/hex"
	"fmt"
	"math"
	"regexp"
	"strconv"
	"strings"
	"time"
)

//计算锅炉总输出功率[KW]=1.163*锅炉水流量[t/h] * (锅炉出水温度[℃]-锅炉回水温度[℃])
//输入：流量ll单位0.1t/h   温度gw,hw单位0.1℃
//返回功率，单位kw
func CalcScgl(ll, gw, hw int) int {
	p := gw - hw
	if p <= 0 || ll <= 0 {
		return 0
	}
	gl_kw := float64(1.163) * float64(ll) / 10.0 * float64(p) / 10.0
	return int(gl_kw)
}

type RfMeta struct {
	ByteSize  int    //字节数
	FieldType string //类型代码,默认值u:小写字母:小端字节序;大写字母:大端字节序；
	FieldCode string //数据代码
}

//解析记录定义字符串，meta:=数据项定义字符串,数据项定义字符串,...
//数据项定义字符串:= [数据项代码]:<数据项字节数>+[数据项类型代码]
//数据项代码，数据项类型代码为可以缺失，数据项类型代码默认为-
//小写字母:小端字节序;大写字母:大端字节序；
// '-'表示忽略此数据;i:有符号整形；u:无符号整形
//返回:数据项代码,数据项字节数,数据项类型代码,数据项定义解析错误
func ParseRfMeta(meta string) []*RfMeta {
	a := strings.Split(meta, ",")
	rfm := make([]*RfMeta, len(a))
	// fsize, fcode, ftype := make([]int, len(a)), make([]string, len(a)), make([]string, len(a))
	// ferr := make([]error, len(a))
	ptn, _ := regexp.Compile(`\s*(?:([a-zA-Z0-9_]+):)?([1-9]+)([a-zA-Z-]?)\s*`)
	for i, m := range a {
		//数据项解码格式解析：数据项代码,数据项字节数,数据项类型
		if ps := ptn.FindStringSubmatch(m); ps != nil {
			rfm[i] = &RfMeta{FieldCode: ps[1]}
			ftype := ps[3]
			if ftype == "" {
				ftype = "-"
			}
			rfm[i].FieldType = ftype
			rfm[i].ByteSize, _ = strconv.Atoi(ps[2])
		}
	}
	return rfm
}
func DecSplit(buf []byte, rfLen []int) [][]byte {
	dats := make([][]byte, len(rfLen))
	pBuf := 0 //缓冲器指针
	for i, n := range rfLen {
		pEnd := pBuf + n
		dats[i] = buf[pBuf:pEnd]
		pBuf = pEnd
	}
	return dats
}

//数组转置，头尾调换
func ReverseArray(ar []byte) {
	for l, r := 0, len(ar)-1; l < r; {
		ar[l], ar[r] = ar[r], ar[l]
		l++
		r--
	}
}

func DecToInt(buf []byte, ftype string) int {
	var val int

	switch len(buf) {
	case 1:
		switch ftype {
		case "I", "i":
			val = int(int8(buf[0]))
		default:
			val = int(uint8(buf[0]))
		}
	case 2:
		var h, l uint16
		switch ftype {
		case "i":
			h, l = uint16(buf[1]), uint16(buf[0])
			val = int(int16(h<<8 | l))
		case "I":
			h, l = uint16(buf[0]), uint16(buf[1])
			val = int(int16(h<<8 | l))
		case "u":
			h, l = uint16(buf[1]), uint16(buf[0])
			val = int(h<<8 | l)
		case "U":
			h, l = uint16(buf[0]), uint16(buf[1])
			val = int(h<<8 | l)
		}
	}

	return val
}

// /**解析响应数组为数据项:	fjdz:1u,2u,4-,...
// [数据代码:]<字节数>[类型代码]	=>	int|string00
// 类型代码,默认值u:小写字母:小端字节序;大写字母:大端字节序；
// 	'-'表示忽略此数据;i:有符号整形；u:无符号整形
// **/
// func DecodeDat(res []byte, datHeader string) map[string]interface{} {
// 	dat := make(map[string]interface{})
// 	var resAddr int //数据项地址
// 	ptn, _ := regexp.Compile("(?:([a-zA-Z0-9_]+):)?([1-9]+)([a-zA-Z-]?)")
// 	// log.Println(hex.EncodeToString(res))
// 	for i, hn := range strings.Split(datHeader, ",") {
// 		hn = strings.TrimSpace(hn)
// 		//数据项解码格式解析：数据项代码,数据项字节数,数据项类型
// 		dcd, dlen, dtype := fmt.Sprintf("d%02x", resAddr), 2, "u"
// 		if ps := ptn.FindStringSubmatch(hn); ps == nil {
// 			panic(fmt.Sprintf("第%d数据项格式错误:%s", i, hn))
// 		} else {
// 			if ps[1] != "" {
// 				dcd = ps[1]
// 			}
// 			dlen, _ = strconv.Atoi(ps[2])
// 			dtype = ps[3]
// 			//				dtype = []rune(ps[3])[0]
// 		}
// 		if dtype == "-" {
// 			resAddr += dlen
// 			continue
// 		}

// 		//数据解码
// 		switch dlen {
// 		case 1: //单字节数据不作断线判断，状态位受影响
// 			//			if 0xfe == res[resAddr] {
// 			//				dat[dcd] = "--"
// 			//				break
// 			//			}
// 			//数据类型处理
// 			if strings.Index("iI", dtype) >= 0 {
// 				dat[dcd] = int(int8(res[resAddr]))
// 			} else { //if strings.Index("uU", dtype) >= 0
// 				dat[dcd] = int(uint8(res[resAddr]))
// 			}
// 			break

// 		case 2:
// 			lv, hv := res[resAddr], res[resAddr+1]
// 			if dtype >= "A" && dtype <= "Z" { //大端字节序
// 				lv, hv = hv, lv
// 			}
// 			if 0xfe == hv && 0xef == lv { //断线检测
// 				ek := dcd
// 				t, has := gl_rtds_errtimes[ek]
// 				if !has {
// 					t = 1
// 				} else {
// 					t = t + 1
// 					//					atomic.AddInt32()
// 				}
// 				gl_rtds_errtimes[ek] = t
// 				if t > appCfg.txErrMaxTimes {
// 					dat[dcd] = "-X-"
// 				}
// 				break
// 			}
// 			if 0xfe == hv && 0xee == lv { //短路
// 				ek := dcd
// 				t, has := gl_rtds_errtimes[ek]
// 				if !has {
// 					t = 1
// 				} else {
// 					t = t + 1
// 				}
// 				gl_rtds_errtimes[ek] = t
// 				if t > appCfg.txErrMaxTimes {
// 					dat[dcd] = "-#-"
// 				}
// 				break
// 			}
// 			//数据类型处理
// 			if strings.Index("iI", dtype) >= 0 {
// 				val := int16(uint16(hv)<<8 | uint16(lv))
// 				dat[dcd] = int(val)
// 			} else { //if strings.Index("uU", dtype) >= 0
// 				val := uint16(hv)<<8 | uint16(lv)
// 				dat[dcd] = int(val)
// 			}
// 		}

// 		// log.Println(i, hn, dcd, dlen, dtype, resAddr, fmt.Sprintf("%x", dat[dcd]), dat[dcd])

// 		resAddr += dlen
// 	}
// 	return dat
// }

//计算状态位：启动设备
func CalcZtw_StartBpq(kzbYxzt, bpqId byte) byte {
	mask := byte(0x80 >> uint(bpqId))
	ztw := kzbYxzt | mask
	return ztw
}

//计算状态位：停止设备
func CalcZtw_StopBpq(kzbYxzt, bpqId byte) byte {
	mask := byte(0x80 >> uint(bpqId))
	mask = ^mask
	ztw := kzbYxzt & mask
	return ztw
}

//计算指定波特率下的接收超时时间/数据帧间隔时间3.5个字符
// 3.5个字符,每个字符11个数据位，传输3.5个字符的时长即为最低超时时间
// 传输一个数据位的时间【毫秒】=波特率/1000
// ≈3.5*11/(波特率/1000)
// 3.5*11/(baud/1000)=3.5*11*1000/baud=3.5*11000/baud
func CalcModbusRecvTimeout(baud int) time.Duration {
	char_time := float64(11*1000) / float64(baud) //单字节传输时长
	// 数据帧间隔时长:5个字节
	timeout := int(math.Ceil(char_time * float64(5)))
	return time.Duration(timeout) * time.Millisecond
}

//字符串解析为整数
//0x开头为16进制，h/H结尾为16进制
func ParseInt(str string) int {
	str = strings.TrimSpace(str)
	if len(str) == 0 {
		return 0
	}
	var y int
	switch {
	case strings.HasPrefix(str, "0x"), strings.HasPrefix(str, "0X"):
		a, _ := strconv.ParseUint(str[2:], 16, 32)
		y = int(a)
	case strings.HasSuffix(str, "H"), strings.HasSuffix(str, "h"):
		str := str[:len(str)-1]
		a, _ := strconv.ParseUint(str, 16, 32)
		y = int(a)
	default:
		a, _ := strconv.ParseInt(str, 10, 32)
		y = int(a)
	}

	return y
}

//将字符串kvstr解析为map,kvstr格式：
//k1:v1,k2:v2,...
//kvps为键值对分隔符，kvs为键值分隔符
func ParseMap(kvstr string, kvps string, kvs string) map[string]string {
	m := make(map[string]string)
	if kvps == "" {
		kvps = ","
	}
	if kvs == "" {
		kvs = ":"
	}
	for _, kv := range strings.Split(kvstr, kvps) {
		kv = strings.TrimSpace(kv)
		if kv == "" || kv == kvs {
			continue
		}
		a := strings.SplitN(kv, kvs, 2)
		k, v := strings.TrimSpace(a[0]), ""
		if len(a) > 1 {
			v = strings.TrimSpace(a[1])
		}
		m[k] = v
	}
	return m
}

//简单加密算法，str明文，返回hex编码密文
func SimpleEncrypt(str string) string {
	o := []byte(str)
	d := make([]byte, len(o))
	for i, b := range o {
		d[i] = b ^ 0xA5
	}
	return hex.EncodeToString(d)
}

//简单解密算法，str为hex编码密码，返回解密后的明文
func SimpleDecrypt(str string) string {
	o, e := hex.DecodeString(str)
	if e != nil {
		return "Err:" + e.Error()
	}
	d := make([]byte, len(o))
	for i, b := range o {
		d[i] = b ^ 0xA5
	}
	return string(d)
}

//二分法在dats数组中查找target值，返回值：查找次数,最接近目标值的数据下标,最接近的目标值,是否精确找到了目标值
func BinarySearch(dats []int, target int) (int, int, int, bool) {
	var l, m, r int = 0, 0, len(dats) - 1    //左、中、右下标
	var lv, mv, rv int = dats[0], 0, dats[r] //左、中、右数值
	var c int                                //下标差，差值
	if target > rv {
		return 0, r, rv, false
	} else if target < lv {
		return 0, l, lv, false
	}
	for i := 0; ; i++ {
		c = r - l
		m = l + c/2
		mv, lv, rv = dats[m], dats[l], dats[r]
		if c <= 1 {
			if c > 0 {
				return i, l, lv, false
			} else {
				return i, r, rv, false
			}
		}
		switch {
		case lv == target:
			return i, l, target, true
		case rv == target:
			return i, r, target, true
		case mv == target:
			return i, m, target, true
		case mv > target:
			r = m
		case mv < target:
			l = m
		}
	}
}

//计算dat数组中字节的CRC16值，多项式 0xA001
func Crc16_A001(dat []byte) uint16 {
	var crc_reg, crc_gen uint32
	crc_reg, crc_gen = 0xFFFF, 0xA001

	for i, l := 0, len(dat); i < l; i++ {
		crc_reg = (uint32(dat[i]) & 0xff) ^ crc_reg
		for j := 8; j > 0; j-- {
			if crc_reg&0x01 == 1 {
				crc_reg >>= 1
				crc_reg ^= crc_gen
			} else {
				crc_reg >>= 1
			}
		}
	}
	return uint16(crc_reg)
}

//按Modbus的RTU协议格式，计算并填写buf报文的crc16值并将值添加到末尾的2个字节:低位，高位
func Crc16_SetModbusRtu(buf []byte) {
	bufLen := len(buf)
	if bufLen <= 2 {
		return
	}
	src := buf[:bufLen-2]
	crc := Crc16_A001(src)
	buf[bufLen-2] = byte(crc)
	buf[bufLen-1] = byte(crc >> 8)
}

//15:04:05.123
func FormatTime_MS(t time.Time) string {
	return fmt.Sprintf("%s.%03d", t.Format("15:04:05"), t.Nanosecond()/1e6)
}

//2006-01-02 15:04:05.123
func FormatTime_L2(t time.Time) string {
	return fmt.Sprintf("%s.%03d", t.Format("2006-01-02 15:04:05"), t.Nanosecond()/1e6)
}

//2006-01-02 15:04:05
func FormatTime_L(t time.Time) string {
	return t.Format("2006-01-02 15:04:05")
}
